■ Xportによる PC(Windows)−PIC間通信
PCのWindowsソフトから Xportをつかって電子回路を制御するには、Lantronix社から提供されている
ComPortRedirectorというソフトをつかうと簡単に制御できます。ComPortRedirectorはXportやWiport
(無線デバイスサーバ)など Lantronix製品からのTCP/IP信号をRS232Cシリアル信号に相互変換する
ソフトです。 これをインストールして仮想COM ポートに所定の設定をおこなうと、Windowsアプリケーション
からはCOMポート経由 RS232Cで制御するのと全く同じに 制御できます。
<試作品仕様>
★ PC(Windows)側
・ アプリケーションソフトから英数字を1〜1000msec毎に1文字づつ以下の経路でPIC側に送る。
仮想COM3ポート(ComPortRedirector) → LANケーブル(TCP/IP) → Xport → PIC
・ 送信している文字、受信している文字を表示すること
・ 受信した文字をエディタリストに表示すること。また必要に応じてエディタリストはクリアできること
★ PIC側
・ 受信した文字をPC側に送信すること
・ XportのCTS、RTSを使ったハードウェアフロー制御を行い、時間のかかる液晶表示中に文字の受信
などを避けたエラーがおこりにくい制御をおこなうこと
・ 液晶(16文字×2桁)には受信した文字を順次表示してゆくこと。文字がいっぱいになったら画面を
クリアしてまた受信した文字を順次表示してゆくこと
<回路図>
・ PIC18F452をつかった場合の回路図を以下に示します。(→回路図ののPDFファイル)
★ハブ+ルータを除いてPCとXportをクロスケーブルで直結しても動作しました。この場合、PCのDHCP(Dynamic
Host
Configuration Protocol)機能はOFFとして手動でURLを設定する必要があります。
<試作品外観> 下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています。
|
<プログラム例 PIC側 > /* ------------------------------------------------------------------ < 構成> Builder(PC) → ComportRedirector→ Xport → PIC18F452 → 16文字キャラクタ液晶 <PC program> 英数字1文字送信 周期1000〜1msec <備考> Xport側 IP address 192.168.0.44 Local port 14001 PC(Windows)側 IP adress 192.168.0.2 TCP port (remote port) 3001 // COM Port: desk/note PC COM3/COM4 2006.9.25 -------------------------------------------------------------------- */ #include "18f452.h" #use delay(clock=40000000) #FUSES EC,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> main(){ unsigned int moji = 0 ; char cmnd; setup_timer_1(T1_INTERNAL |T1_DIV_BY_8); set_tris_c(0b10000000);// 必須 in = RC7 of Rx lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); delay_ms(2000); lcd_clear(); while(1) { cmnd = getc(); if(input(PIN_C0) == 1)putc(cmnd);//XportのCP1端子から送信許可の信号がでていれば送信する //CP1(6番端子)を CTS(Clear To Send 送信許諾)に設定 //CP1は出力ポートモード //CTS信号: 1 = 送信許可 、 0 = 送信不可 output_low(PIN_C2); // XportのCP3端子へ送信禁止信号を出力 RTS= 0 // CP2(8番端子)をRTS(Request To Send 送信要求)) //CP3は入力ポートモード //RTS信号: 1 = 送信許可 、0 = 送信不可 moji++; switch(moji) { case 16: lcd_cmd(0xC0); // 2行目の先頭へ break; case 32: lcd_cmd(0x01); // 全消去 moji = 0; break; default: // break; } lcd_data(cmnd); output_high(PIN_C2); //Xportからの送信許可 RTS = 1 } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home } //************************************************************************************** //************************************************************************************** // < プログラム例 Windows側 > // // このプログラムは C++ Buider Ver.6 でかかれています。 プログラムのソースコード //************************************************************************************** //************************************************************************************** #include <vcl.h> #include <stdio.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "MsTimer" #pragma resource "*.dfm" TForm1 *Form1; HANDLE hPort; // ポートハンドル BYTE bSendBuffer[1]; // 送信データ DWORD dwSendSize; // 送信データサイズ DCB dcb; // DCB構造体 COMMTIMEOUTS Timeout; // COMMTIMEOUTS構造体 BOOL Ret; // 関数戻り値 int n; // ループ用 char In[1]; DWORD lRead; unsigned int count = 47; unsigned long int posCount=0; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // ポート初期化 hPort = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hPort == INVALID_HANDLE_VALUE){ printf("Port could not open.\n"); exit(0); } // 送受信バッファ初期化 Ret = SetupComm(hPort, 512, 512); if(Ret == FALSE){ printf("SetupComm failed.\n"); CloseHandle(hPort); exit(0); } Ret = PurgeComm(hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); if(Ret == FALSE){ printf("PurgeComm failed.\n"); CloseHandle(hPort); exit(0); } /* // タイムアウト設定 [msec] COMMTIMEOUTS構造体で設定 Timeout.ReadIntervalTimeout = 500; // 文字読込時の全体の待ち時間 Timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 Timeout.ReadTotalTimeoutConstant = 500; //読込エラー検出用のタイムアウト時間 Timeout.WriteTotalTimeoutMultiplier = 0; //書き込み1文字あたりの待ち時間 Timeout.WriteTotalTimeoutConstant = 500;//書き込みエラー検出用のタイムアウト時間 */ // タイムアウト設定 [msec] COMMTIMEOUTS構造体で設定 Timeout.ReadIntervalTimeout = 5; // 文字読込時の全体の待ち時間 Timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 Timeout.ReadTotalTimeoutConstant = 5; //読込エラー検出用のタイムアウト時間 Timeout.WriteTotalTimeoutMultiplier = 0; //書き込み1文字あたりの待ち時間 Timeout.WriteTotalTimeoutConstant = 5;//書き込みエラー検出用のタイムアウト時間 Ret = SetCommTimeouts(hPort, &Timeout); if(Ret == FALSE){ printf("SetCommTimeouts failed.\n"); CloseHandle(hPort); exit(0); } // 通信設定 → DCB( デバイス制御ブロック)構造体へのポインタ Ret = GetCommState(hPort, &dcb); if(Ret == FALSE){ printf("GetCommState failed.\n"); CloseHandle(hPort); exit(0); } dcb.BaudRate = 9600; dcb.Parity = 0; dcb.StopBits = ONESTOPBIT; dcb.ByteSize = 8; Ret = SetCommState(hPort, &dcb); if(Ret == FALSE){ printf("SetCommState failed.\n"); CloseHandle(hPort); exit(0); } Button1->Tag = false ; ComboBox1->ItemIndex = 0; MsTimer1->Interval = 1000; RichEdit1->Lines->Clear(); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { // 終了処理 CloseHandle(hPort); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { if(Button1->Tag == false) { Button1->Tag = true; Button1->Caption = "送信停止"; MsTimer1->Enabled = true; } else { Button1->Tag = false; Button1->Caption = "送信開始"; MsTimer1->Enabled = false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::ComboBox1Change(TObject *Sender) { switch(ComboBox1->ItemIndex) { case 0: MsTimer1->Interval = 1000; break; case 1: MsTimer1->Interval = 700; break; case 2: MsTimer1->Interval = 500; break; case 3: MsTimer1->Interval = 300; break; case 4: MsTimer1->Interval = 200; break; case 5: MsTimer1->Interval = 100; break; case 6: MsTimer1->Interval = 70; break; case 7: MsTimer1->Interval = 50; break; case 8: MsTimer1->Interval = 30; break; case 9: MsTimer1->Interval = 20; break; case 10: MsTimer1->Interval = 10; break; case 11: MsTimer1->Interval = 7; break; case 12: MsTimer1->Interval = 5; break; case 13: MsTimer1->Interval = 3; break; case 14: MsTimer1->Interval = 2; break; case 15: MsTimer1->Interval = 1; break; default: break; } } //--------------------------------------------------------------------------- void __fastcall TForm1::MsTimer1Timer(TObject *Sender) { char s[1]; int itemp; AnsiString As; count++; if(count == 58)count = 65; if(count >= 91)count = 48; Label1->Caption = count; sprintf(s,"%c",count); Label3->Caption = s; bSendBuffer[0] = count; // データ送信 Ret = EscapeCommFunction(hPort, SETRTS); if(Ret == FALSE){ printf("EscapeCommFunction failed.\n"); CloseHandle(hPort); exit(0); } Ret = WriteFile(hPort, bSendBuffer, 1, &dwSendSize, NULL); if(Ret == FALSE){ printf("WriteFile failed.\n"); CloseHandle(hPort); exit(0); } if( ReadFile(hPort,In,1,&lRead,NULL)==0){ // ADコンバータの値をunsigned char で読込み 失敗したら itemp = Application->MessageBox("データ入力のパイプ0の読み出しでエラーが発生", "警告", MB_OK ) ; if(itemp == IDYES) return; } sprintf(s,"%c",In[0]); Label2->Caption = s; As = AnsiString(s); // RichEdit1->Lines->Add(As) ; // RichEdit1->Text = As; RichEdit1->SelText = As; if(As == 'Z') RichEdit1->Lines->Add("") ; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { RichEdit1->Lines->Clear(); }
<動作手順>
@ Lantronix社のホームページから ComPortRedirectorとDeviceInstallerをダウンロードしてPCにインストールします。
以下は下記の場合のものです
Xport側 IP address 192.168.0.44 Local port
14001
PC(Windows)側 IP adress 192.168.0.2 TCP port (remote
port) 3001
A Redirectorを起動して以下の画面になるように設定します
B 一方 DeviceInstallerを下記のように設定します。
C 下記のようなPC操作画面から英数字をPIC側に送信します。送信した文字のASCIIコードとASCII文字が上段に
また 受信した文字のASCII文字が下段に表示されています。 下記の画面は50msec毎に1文字ずつ送られて
いる場合のものです。送信周期はコンボボックスで1〜1000msecの値が選択できるようになっています。
エディットボックスにはPICからこのソフトに送られてきた文字が0から順番に並んでZまで表示すると改行する
ようになっています。またclearボタンでいつでもこのエディットボックスはクリアできます。
送信した文字が J で受信した文字が
G となっていて送信と受信でかなりの時差が発生していることがわかり
ます。
D PIC側の液晶には送信されてきた順番に文字が表示されるようになっています。文字がいっぱいになると
液晶がクリアされて 再び送信されてきた文字が表示されます。(写真参照)